package org.mch.comm.db.mhandler;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.mch.comm.exec.MsgException;
import org.mch.comm.itf.ItfMHandler;
import org.mch.comm.lang.MDate;
import org.mch.comm.velocity.MVelocityEngine;
import org.mch.comm.velocity.VelBeanData;
import org.mch.comm.velocity.VelFieldData;
import org.mch.func.db.tool.DBInfoUtil;
import org.mch.func.entity.TableColumnEO;

/**
 * 描述：生成 Hibernate实体对象处理器；<BR/>
 * 
 * @author MCH；Date：2008-06-18；<BR/>
 *
 */
public class GenerateHibernateEOHandler implements ItfMHandler<String> {

	private String tableName;

	public GenerateHibernateEOHandler(String tableName) {
		super();
		this.tableName = tableName;
	}

	protected String buildClassName() {
		String tablecode = firstLetterUpperCase(getTableName().toLowerCase()) + "EO";
		String[] tmp = tablecode.split("_");
		if (tmp != null && tmp.length > 1) {
			StringBuffer tmpcode = new StringBuffer();
			for (int i = 0; i < tmp.length; i++) {
				if (i == 0) {
					tmpcode.append(tmp[i]);
				} else {
					tmpcode.append(firstLetterUpperCase(tmp[i]));
				}
			}
			return tmpcode.toString();
		}
		return tablecode;
	}

	public String handle() throws Exception {
		Map<String, TableColumnEO> types = DBInfoUtil.getColmnTypes(getTableName());

		if (types == null) {
			return "";
		}
		String table_pk = DBInfoUtil.getTablePKField(getTableName());
		if (table_pk == null || table_pk.trim().equals("")) {
			throw new MsgException("表：【" + getTableName() + "】 没有主键，请检查");
		}

		String[] fieldnames = (String[]) types.keySet().toArray(new String[0]);

		String beanClassName = buildClassName();

		VelBeanData beanData = new VelBeanData();
		beanData.setPKFieldName(table_pk);
		beanData.setTableName(getTableName());
		beanData.setVersionUID(System.nanoTime() + "L");
		beanData.setClassName(beanClassName);
		beanData.setAuthorName("MCH");
		beanData.setCreateDate(new MDate(new Date()).toString());
		beanData.setClassAnnotation("@Entity\n@Table(name = \"" + getTableName() + "\")");

		List<VelFieldData> fieldList = new ArrayList<VelFieldData>();
		beanData.setFieldList(fieldList);

		for (int i = 0; i < fieldnames.length; i++) {
			VelFieldData fieldData = new VelFieldData();
			TableColumnEO colinfo = types.get(fieldnames[i]);
			String colname = fieldnames[i].toLowerCase();
			String coltypestr = byColTypeGetHibernateVOJavaType(colinfo.coltype, colinfo.precision, colinfo.scale);

			fieldData.setFieldDesc(colname);
			fieldData.setFieldModifier("private");
			fieldData.setFieldName(colname);
			fieldData.setFieldType(coltypestr);

			if (table_pk.equalsIgnoreCase(colname)) {
				fieldData.setFieldAnnotation("@Id@GeneratedValue(strategy = GenerationType.AUTO)");
			} else {
				fieldData.setFieldAnnotation("@Column");
			}

			fieldData.setMethodGetName("get" + firstLetterUpperCase(colname));
			fieldData.setMethodSetName("set" + firstLetterUpperCase(colname));

			fieldList.add(fieldData);
		}

		return new MVelocityEngine().getTemplateStrEO("resource/vmtemplate/HibernateEO.vm", beanData);
	}

	public String firstLetterUpperCase(String str) {
		return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
	}

	public String getTableName() {
		return tableName;
	}

	protected String byColTypeGetHibernateVOJavaType(int coltype, int precision, int scale) {
		switch (coltype) {
			case 1: // CHAR
				if (precision == 19)
					return "MDateTime";
				if (precision == 10)
					return "MDate";
				if (precision == 8)
					return "MTime";
				if (precision == 1)
					return "MBoolean";
				else
					return "String";

			case 12: // VARCHAR
				if (precision == 10)
					return "MDate";
				if (precision == 19)
					return "MDateTime";
				if (precision == 8)
					return "MTime";
				else
					return "String";

			case 8: // '\b'
				return "MDouble";

			case 6: // '\006'
				return "MDouble";

			case 2: // '\002'
				if (scale > 0)
					return "MDouble";
				if (scale == 0)
					if (precision <= 10)
						return "Integer";
					else
						return "Long";
				// fall through

			case 3: // '\003'
				if (scale > 0)
					return "MDouble";
				if (scale == 0)
					if (precision <= 10)
						return "Integer";
					else
						return "Long";
				// fall through

			case 4: // '\004'
				return "Integer";

			case 5: // '\005'
				return "Integer";

			case 7: // '\007'
			case 9: // '\t'
			case 10: // '\n'
			case 11: // '\013'
			default:
				return "String";
		}
	}
}
